﻿using System;
using System.Collections;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace EarthLineTransmitter
{
    public class ByteEventArgs : EventArgs
    {
        public byte[] Bytes
        {
            get { return _bytes; }
        }

        public ByteEventArgs(byte[] bytes)
        {
            if (null != bytes && 0 < bytes.Length)
            {
                _bytes = new byte[bytes.Length];
                Array.Copy(bytes, _bytes, bytes.Length);
            }
        }

        private byte[] _bytes = null;
    }

    public class ClientHandler
    {
        public event EventHandler OnReceiveData;

        public ClientHandler(TcpClient ClientSocket)
        {
            ClientSocket.ReceiveTimeout = 100; // 100 miliseconds
            this._clientSocket = ClientSocket;
            _networkStream = ClientSocket.GetStream();
            _bytes = new byte[ClientSocket.ReceiveBufferSize];
            _continueProcess = true;
        }

        public bool isOnline()
        {
            bool part1 = _clientSocket.Client.Poll(1000, SelectMode.SelectRead);
            bool part2 = (_clientSocket.Client.Available == 0);
            if ((part1 && part2) || !_clientSocket.Client.Connected)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        public void Close()
        {
            lock (_lock)
            {
                _continueProcess = false;
                _networkStream.Close();
                _clientSocket.Close();
            }
        }

        public void write(byte[] data)
        {
            if (!Alive)
            {
                return;
            }

            if (null == data)
            {
                return;
            }
            if (!_networkStream.CanWrite)
            {
                return;
            }
            try
            {
                lock (_lock)
                {
                    _networkStream.Write(data, 0, data.Length);
                    _networkStream.Flush();
                }
                string str = Encoding.ASCII.GetString(data);
                Console.WriteLine("[{0}][write]  {1}", DateTime.Now.ToString("HH:mm:ss:fff"), str);
            }
            catch (Exception)
            {
                Console.WriteLine("Write error");
            }
        }

        public bool Alive
        {
            get
            {
                return _continueProcess;
            }
        }

        public void Process()
        {
            Console.WriteLine("Client Process  ======1");
            if (!_continueProcess)
            {
                return;
            }
            Console.WriteLine("Client Process  ======2");
            if (!isOnline())
            {
                Close();
                Console.WriteLine("Conection is broken!");
                return;
            }
            Console.WriteLine("Client Process  ======3");
            try
            {
                if (_networkStream.DataAvailable)
                {
                    Console.WriteLine("Client Process  ======4");
                    int BytesRead = 0;
                    lock (_lock)
                    {
                        BytesRead = _networkStream.Read(_bytes, 0, (int)_bytes.Length);
                    }
                    if (BytesRead > 0)
                    {
                        byte[] data = new byte[BytesRead];
                        Array.Copy(_bytes, 0, data, 0, BytesRead);
                        string str = Encoding.ASCII.GetString(data);
                        Console.WriteLine("[{0}][read ]  {1}", DateTime.Now.ToString("HH:mm:ss:fff"), str);
                        lock (_lock)
                        {
                            doReceiveData(data);
                        }
                        Console.WriteLine("[{0}][read1]  {1}", DateTime.Now.ToString("HH:mm:ss:fff"), "");
                    }
                    Console.WriteLine("Client Process  ======5");
                }
                Console.WriteLine("Client Process  ======6");
            }
            catch (IOException)
            {
                // All the data has arrived; put it in response.
                //ProcessDataReceived();
                Console.WriteLine("Read error");
            }
            catch (SocketException)
            {
                Close();
                Console.WriteLine("Conection is broken!");
            }

        }  // Process()

        protected void doReceiveData(byte[] data)
        {
            if (null != OnReceiveData)
            {
                OnReceiveData(this, new ByteEventArgs(data));
            }
        }

        private TcpClient _clientSocket;
        private NetworkStream _networkStream;
        bool _continueProcess = false;
        private byte[] _bytes;       // Data buffer for incoming data.
        private StringBuilder _sb = new StringBuilder(); // Received data string.
        private string _data = null; // Incoming data from the client.
        private object _lock = new object();

    } // class ClientHandler 

    public class ClientConnectionPool
    {
        // Creates a synchronized wrapper around the Queue.
        private Queue _syncdQ = Queue.Synchronized(new Queue());

        public void Enqueue(ClientHandler client)
        {
            _syncdQ.Enqueue(client);
        }

        public ClientHandler Dequeue()
        {
            return (ClientHandler)(_syncdQ.Dequeue());
        }

        public int Count
        {
            get { return _syncdQ.Count; }
        }

        public object SyncRoot
        {
            get { return _syncdQ.SyncRoot; }
        }

        public IEnumerable Enumerator
        {
            get { return _syncdQ; }
        }

    } // class ClientConnectionPool

    public class ClientService
    {
        public event EventHandler OnClientLeave;

        const int NUM_OF_THREAD = 1;

        private ClientConnectionPool _connectionPool;
        private bool _continueProcess = false;
        private Thread[] _threadTask = new Thread[NUM_OF_THREAD];

        public ClientService(ClientConnectionPool ConnectionPool)
        {
            this._connectionPool = ConnectionPool;
        }

        public void Start()
        {
            _continueProcess = true;
            // Start threads to handle Client Task
            for (int i = 0; i < _threadTask.Length; i++)
            {
                _threadTask[i] = new Thread(new ThreadStart(this.Process));
                _threadTask[i].Start();
            }
        }

        private void Process()
        {
            string str = "i am receive thread";
            while (_continueProcess)
            {
                Console.WriteLine(str + "--1");
                ClientHandler client = null;
                bool removed = false;
                lock (_connectionPool.SyncRoot)
                {
                    Console.WriteLine(str + "--2");
                    if (_connectionPool.Count > 0)
                    {
                        client = _connectionPool.Dequeue();
                        Console.WriteLine(str + "--3");
                        if (client != null)
                        {
                            client.Process(); // Provoke client
                            Console.WriteLine(str + "--4");
                            if (client.Alive)
                            {
                                _connectionPool.Enqueue(client);
                            }
                            else
                            {
                                removed = true;
                            }
                        }
                        Console.WriteLine(str + "--5");
                    }
                }
                if (removed)
                {
                    if (null != OnClientLeave)
                    {
                        OnClientLeave(this, EventArgs.Empty);
                    }
                }

                Console.WriteLine(str + "--2");
                Thread.Sleep(100);
            }
            Console.WriteLine("Client Service Exit");
        }

        public void Stop()
        {
            _continueProcess = false;
            for (int i = 0; i < _threadTask.Length; i++)
            {
                if (_threadTask[i] != null && _threadTask[i].IsAlive)
                    _threadTask[i].Join(1000);
            }

            // Close all client connections
            while (_connectionPool.Count > 0)
            {
                ClientHandler client = _connectionPool.Dequeue();
                client.Close();
                Console.WriteLine("Client connection is closed!");
            }
        }

        public void write(byte[] bytes)
        {
            ArrayList list = new ArrayList();
            IEnumerable iEnumerator = _connectionPool.Enumerator;
            lock (_connectionPool.SyncRoot)
            {
                foreach (ClientHandler handler in iEnumerator)
                {
                    list.Add(handler);
                    //handler.write(bytes);
                }
            }
            for (int i = 0; i < list.Count; i++)
            {
                ClientHandler handler = (ClientHandler)list[i];
                handler.write(bytes);
            }
        }

    } // class ClientService

    public class TcpServer
    {
        //有数据上传
        public event EventHandler OnData;
        //服务端口
        public int Port { get; set; }

        public string Name { get; set; }

        public TcpServer()
        {
        }

        public virtual void start()
        {
            if (_started)
            {
                return;
            }
            _started = true;
            _listener = new TcpListener(IPAddress.Any, Port);

            _clientConnectionPool = new ClientConnectionPool();
            _clientService = new ClientService(_clientConnectionPool);
            _clientService.OnClientLeave += _clientService_OnClientLeave;
            _clientService.Start();

            _thread = new Thread(new ThreadStart(listentTcpClient));
            _thread.Start();
        }

        public void stop()
        {
            if (!_started)
            {
                return;
            }
            _started = false;
            _thread.Join();
            _clientService.Stop();
            _clientService = null;
            _clientConnectionPool = null;
            _listener = null;
        }

        //转发数据
        public virtual void transmit(EventArgs eventArgs)
        {
            ByteEventArgs args = (ByteEventArgs)eventArgs;
            byte[] bytes = args.Bytes;
            _clientService.write(bytes);
        }

        //待机，不接受客户端连接，并断开已连接的客户端
        public void idle()
        {
            _idle = true;
            ArrayList list = new ArrayList();
            lock (_clientConnectionPool.SyncRoot)
            {
                while (0 < _clientConnectionPool.Count)
                {
                    ClientHandler handler = _clientConnectionPool.Dequeue();
                    list.Add(handler);
                }
            }
            for (int i = 0; i < list.Count; i++)
            {
                ClientHandler handler = (ClientHandler)list[i];
                handler.Close();
            }
        }


        //工作状态，接受客户端连接
        public void work()
        {
            _idle = false;
        }

        protected virtual void doClientLeave(int clientCount)
        {

        }

        protected virtual void doClientEnter()
        {

        }

        private void listentTcpClient()
        {
            int clientCount = 0;
            _listener.Start();
            Console.WriteLine("Waiting for a {0} connection...", Name);
            while (_started)
            {
                Thread.Sleep(100);
                if (_idle)
                {
                    continue;
                }
                if (!_listener.Pending())
                {
                    continue;
                }
                TcpClient client = _listener.AcceptTcpClient();
                if (null != client)
                {
                    ClientHandler handler = new ClientHandler(client);
                    handler.OnReceiveData += Handler_OnReceiveData;
                    _clientConnectionPool.Enqueue(handler);
                    Console.WriteLine("{0} Clients: {1}", Name, _clientConnectionPool.Count);
                    doClientEnter();
                }

            }
            _listener.Stop();
        }

        private void Handler_OnReceiveData(object sender, EventArgs e)
        {
            if (null != OnData)
            {
                OnData(this, e);
            }
        }

        private void _clientService_OnClientLeave(object sender, EventArgs e)
        {
            int count = _clientConnectionPool.Count;
            doClientLeave(count);
        }


        private Thread _thread;
        private TcpListener _listener;
        private bool _started = false;
        private ClientService _clientService;
        private ClientConnectionPool _clientConnectionPool;
        private bool _idle = false;
    }

    public class WfServer : TcpServer
    {

        //转发地线控制器数据
        public override void transmit(EventArgs eventArgs)
        {
            base.transmit(eventArgs);
        }
    }

    public class EarthLineServer : TcpServer
    {
        //地线控制器启动(有Tcp客户端接入)
        public event EventHandler OnTurnOn;
        //地线控制器关闭(客户端断开)
        public event EventHandler OnTurnOff;

        //转发五防子站数据    
        public override void transmit(EventArgs eventArgs)
        {
            base.transmit(eventArgs);
        }

        protected override void doClientLeave(int clientCount)
        {
            if (1 > clientCount)
            {
                if (_inited)
                {
                    _inited = false;
                    if (null != OnTurnOff)
                    {
                        OnTurnOff(this, EventArgs.Empty);
                    }

                }
            }
        }

        protected override void doClientEnter()
        {
            if (!_inited)
            {
                _inited = true;
                if (null != OnTurnOn)
                {
                    OnTurnOn(this, EventArgs.Empty);
                }
            }
        }

        private bool _inited = false;
    }

    public class SendInfo
    {
        public TcpServer Server { get { return _server; } }
        public EventArgs Args { get { return _args; } }
        public bool Alive { get { return _alive; } }

        public SendInfo(TcpServer server, EventArgs args)
        {
            _server = server;
            _args = args;
        }

        public void Process()
        {
            _server.transmit(_args);
            _alive = false;
        }

        public void Close()
        {

        }

        private TcpServer _server;
        private EventArgs _args;
        private bool _alive = true;
    }


    public class ClientSendPool
    {
        // Creates a synchronized wrapper around the Queue.
        private Queue _syncdQ = Queue.Synchronized(new Queue());

        public void Enqueue(SendInfo info)
        {
            _syncdQ.Enqueue(info);
        }

        public SendInfo Dequeue()
        {
            return (SendInfo)(_syncdQ.Dequeue());
        }

        public int Count
        {
            get { return _syncdQ.Count; }
        }

        public object SyncRoot
        {
            get { return _syncdQ.SyncRoot; }
        }

        public IEnumerable Enumerator
        {
            get { return _syncdQ; }
        }

    } // class ClientSendPool

    public class SendService
    {
        public event EventHandler OnClientLeave;

        const int NUM_OF_THREAD = 1;

        private ClientSendPool _sendPool;
        private bool _continueProcess = false;
        private Thread[] _threadTask = new Thread[NUM_OF_THREAD];

        public SendService(ClientSendPool sendPool)
        {
            this._sendPool = sendPool;
        }

        public void Start()
        {
            _continueProcess = true;
            // Start threads to handle Send Task
            for (int i = 0; i < _threadTask.Length; i++)
            {
                _threadTask[i] = new Thread(new ThreadStart(this.Process));
                _threadTask[i].Start();
            }
        }

        private void Process()
        {
            while (_continueProcess)
            {

                SendInfo info = null;
                lock (_sendPool.SyncRoot)
                {
                    if (_sendPool.Count > 0)
                    {
                        info = _sendPool.Dequeue();
                        if (info != null)
                        {
                            info.Process();
                            if (info.Alive)
                            {
                                _sendPool.Enqueue(info);
                            }
                        }
                    }
                }
                Thread.Sleep(100);
            }
            Console.WriteLine("Send Service Exit");
        }

        public void Stop()
        {
            _continueProcess = false;
            for (int i = 0; i < _threadTask.Length; i++)
            {
                if (_threadTask[i] != null && _threadTask[i].IsAlive)
                    _threadTask[i].Join();
            }
            while (_sendPool.Count > 0)
            {
                SendInfo info = _sendPool.Dequeue();
                info.Close();
            }
        }

    } // class SendService



}